package com.palominolabs.metrics.jersey; import com.codahale.metrics.ConsoleReporter; import com.codahale.metrics.Counter; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; import com.google.common.collect.Sets; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.servlet.GuiceFilter; import com.google.inject.servlet.ServletModule; import com.ning.http.client.AsyncHttpClient; import com.palominolabs.config.ConfigModuleBuilder; import com.palominolabs.jersey.dispatchwrapper.ResourceMethodWrappedDispatchModule; import com.sun.jersey.api.core.ResourceConfig; import com.sun.jersey.guice.JerseyServletModule; import com.sun.jersey.guice.spi.container.servlet.GuiceContainer; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.slf4j.bridge.SLF4JBridgeHandler; import javax.management.AttributeNotFoundException; import javax.management.InstanceNotFoundException; import javax.management.MBeanException; import javax.management.MalformedObjectNameException; import javax.management.ReflectionException; import javax.servlet.DispatcherType; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.GET; import javax.ws.rs.Path; import java.io.IOException; import java.util.EnumSet; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.SortedMap; import java.util.concurrent.ExecutionException; import java.util.logging.LogManager; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; public class FullStackTest { private static final int PORT = 18080; private Server server; private AsyncHttpClient httpClient; private ConsoleReporter consoleReporter; private MetricRegistry metricRegistry; @Before public void setUp() throws Exception { LogManager.getLogManager().reset(); SLF4JBridgeHandler.install(); final MetricRegistry registry = new MetricRegistry(); metricRegistry = registry; final Map<String, String> initParams = new HashMap<>(); initParams.put(ResourceConfig.PROPERTY_RESOURCE_FILTER_FACTORIES, HttpStatusCodeCounterResourceFilterFactory.class.getCanonicalName()); initParams.put(ResourceConfig.FEATURE_DISABLE_WADL, "true"); Injector injector = Guice.createInjector(new AbstractModule() { @Override protected void configure() { binder().requireExplicitBindings(); install(new ResourceMethodWrappedDispatchModule()); install(new ServletModule() { @Override protected void configureServlets() { serve("/*").with(GuiceContainer.class, initParams); } }); install(new JerseyServletModule()); bind(GuiceFilter.class); bind(GuiceContainer.class); bind(EnabledOnClass.class); bind(DisabledOnClass.class); bind(EnabledOnClassDisabledOnMethod.class); install(new ConfigModuleBuilder().build()); install(new ResourceMethodMetricsModule()); bind(MetricRegistry.class).annotatedWith(JerseyResourceMetrics.class).toInstance(registry); } }); httpClient = new AsyncHttpClient(); server = getServer(injector.getInstance(GuiceFilter.class)); server.start(); consoleReporter = ConsoleReporter.forRegistry(registry).build(); } @After public void tearDown() throws Exception { consoleReporter.report(); consoleReporter.stop(); server.stop(); } @Test public void testFullStack() throws IOException, ExecutionException, InterruptedException, MalformedObjectNameException, AttributeNotFoundException, MBeanException, ReflectionException, InstanceNotFoundException { assertEquals(200, httpClient.prepareGet("http://localhost:" + PORT + "/enabledOnClass").execute().get().getStatusCode()); // these other two resource classes should not have metrics assertEquals(200, httpClient.prepareGet("http://localhost:" + PORT + "/disabledOnClass").execute().get().getStatusCode()); assertEquals(200, httpClient.prepareGet("http://localhost:" + PORT + "/enabledOnClassDisabledOnMethod").execute().get() .getStatusCode()); SortedMap<String, Timer> timers = metricRegistry.getTimers(); // check names Set<String> timerNames = Sets.newHashSet( "com.palominolabs.metrics.jersey.FullStackTest$EnabledOnClass./enabledOnClass GET timer"); assertEquals(timerNames, timers.keySet()); SortedMap<String, Counter> counters = metricRegistry.getCounters(); Set<String> counterNames = Sets.newHashSet( "com.palominolabs.metrics.jersey.FullStackTest$EnabledOnClass./enabledOnClass GET 200 counter"); assertEquals(counterNames, counters.keySet()); // check values Timer timer = timers.get(timerNames.iterator().next()); assertEquals(1, timer.getCount()); assertTrue(timer.getMeanRate() > 0D); Counter counter = counters.get(counterNames.iterator().next()); assertEquals(1, counter.getCount()); } private Server getServer(GuiceFilter filter) { Server server = new Server(PORT); ServletContextHandler servletHandler = new ServletContextHandler(); servletHandler.addServlet(new ServletHolder(new HttpServlet() { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setStatus(HttpServletResponse.SC_NOT_FOUND); resp.setContentType("text/plain"); resp.setContentType("UTF-8"); resp.getWriter().append("404"); } }), "/*"); // add guice servlet filter servletHandler.addFilter(new FilterHolder(filter), "/*", EnumSet.allOf(DispatcherType.class)); server.setHandler(servletHandler); return server; } @Path("enabledOnClass") @ResourceMetrics public static class EnabledOnClass { @GET public String get() { return "ok"; } } @Path("disabledOnClass") @ResourceMetrics(statusCodeCounter = false, timer = false) public static class DisabledOnClass { @GET public String get() { return "ok"; } } @Path("enabledOnClassDisabledOnMethod") @ResourceMetrics public static class EnabledOnClassDisabledOnMethod { @GET @ResourceMetrics(statusCodeCounter = false, timer = false) public String get() { return "ok"; } } }